package com.ys168.gam.searcher;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import com.ys168.gam.bean.EngineInfo;
import com.ys168.gam.bean.SearchConditionInfo;
import com.ys168.gam.util.ConfigLoader;

/**
 * @author Jason Krebs
 * @since 2015年6月9日
 */
public abstract class BaseSearcher {

    protected static final String PAGE_SIZE = "{PAGE_SIZE}";
    protected static final String PAGE_INDEX = "{PAGE_INDEX}";
    protected static final String KEY_WORD = "{KEY_WORD}";
    protected static final String WIDTH = "{WIDTH}";
    protected static final String HEIGHT = "{HEIGHT}";
    protected static final String IMAGE_SIZE = "{IMG_SIZE}";

    protected EngineInfo engineInfo;
    protected SearchConditionInfo searchConditionInfo;

    protected BaseSearcher(EngineInfo engineInfo, SearchConditionInfo searchConditionInfo) {
        this.engineInfo = engineInfo;
        this.searchConditionInfo = searchConditionInfo;
    }

    // @formatter:off
    protected URL buildSearchUrl(int pageIndex) {
        String baseUrl = engineInfo.getUrl();
        try {
            String url = baseUrl
                    .replace(PAGE_INDEX, String.valueOf(pageIndex))
                    .replace(PAGE_SIZE, String.valueOf(engineInfo.getPageSize()))
                    .replace(KEY_WORD, searchConditionInfo.getWord())
                    .replace(IMAGE_SIZE, searchConditionInfo.getImageSizeCode())
                    .replace(WIDTH, String.valueOf(searchConditionInfo.getWidth()))
                    .replace(HEIGHT,String.valueOf(searchConditionInfo.getHeight()));

            return new URL(url);
        }
        catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return null;
    }//@formatter:on

    private String getSource(URL url) throws Exception {

        HttpURLConnection conn = null;
        InputStream input = null;
        BufferedReader reader = null;
        StringBuilder sbuilder = new StringBuilder();

        try {
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");

            int timeout = ConfigLoader.getSearchTimeout();
            if (timeout > 0) {
                conn.setConnectTimeout(timeout);
            }

            initConnectionParameter(conn);

            if (conn.getResponseCode() != 200) {
                throw new Exception("responseCode:" + conn.getResponseCode() + ",message:" + conn.getResponseMessage());
            }

            input = conn.getInputStream();
            reader = new BufferedReader(new InputStreamReader(input));

            String temp = null;
            while ((temp = reader.readLine()) != null) {
                sbuilder.append(temp);
            }
        }
        catch (Exception e) {
            throw e;
        }
        finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (input != null) {
                    input.close();
                }
                if (conn != null) {
                    conn.disconnect();
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }

        return sbuilder.toString();
    }

    protected void initConnectionParameter(URLConnection connection) {
    }

    protected abstract List<URL> parse(String source) throws Exception;

    /**
     * 
     * @param engineCode
     * @param word
     * @return
     * @throws Exception
     */
    public final List<URL> search() throws Exception {
        List<URL> urls = new ArrayList<URL>();
        int pageIndex = searchConditionInfo.getStartPageIndex();
        do {
            urls.addAll(searchByPage(pageIndex++));
        } while (!urls.isEmpty() && urls.size() < searchConditionInfo.getDownloadSize());

        while (urls.size() > searchConditionInfo.getDownloadSize()) {
            urls.remove(urls.size() - 1);
        }

        return urls;
    }

    public List<URL> searchByPage(int pageIndex) throws Exception {
        URL searchUrl = buildSearchUrl(pageIndex);
        String source = getSource(searchUrl);

        return parse(source);
    }

}
